package com.hyt.it.ogt.ks.service.es;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.it.ogt.ks.config.KsBizRunTimeException;
import com.hyt.it.ogt.ks.enums.BizStatusCode;
import com.hyt.it.ogt.ks.enums.log.AdminOperatorLogType;
import com.hyt.it.ogt.ks.enums.log.ApplyCheckState;
import com.hyt.it.ogt.ks.enums.log.LogEventType;
import com.hyt.it.ogt.ks.enums.log.WebsocketMsgSendState;
import com.hyt.it.ogt.ks.es.CandidateOperationTrackLogDTO;
import com.hyt.it.ogt.ks.feign.KwClient;
import com.hyt.it.ogt.ks.feign.es.EsClient;
import com.hyt.it.ogt.ks.feign.model.ExamCandidate;
import com.hyt.it.ogt.ks.feign.model.es.EsApplyCheckRecord;
import com.hyt.it.ogt.ks.feign.model.es.EsExceptionManageRecord;
import com.hyt.it.ogt.ks.model.entity.ApplyCheck;
import com.hyt.it.ogt.ks.model.entity.ApplyCheckMsg;
import com.hyt.it.ogt.ks.model.entity.CandidateLogOther;
import com.hyt.it.ogt.ks.service.IApplyCheckMsgService;
import com.hyt.it.ogt.ks.service.IApplyCheckService;
import com.hyt.it.ogt.ks.service.ICandidateLogOtherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 考试对接es服务
 *
 * @author zhoumiao
 * @since 2022/12/14 10:43
 **/
@Service
@Slf4j
public class IEsAndDbServiceImpl implements IEsAndDbService {

    @Autowired
    private EsClient esClient;
    @Autowired
    private IApplyCheckService applyCheckService;
    @Autowired
    private ICandidateLogOtherService candidateLogOtherService;
    @Autowired
    private KwClient kwClient;
    @Autowired
    private IApplyCheckMsgService applyCheckMsgService;

    @Override
    public void saveOrUpdateApplyCheckByIds(Set<String> applyCheckIds) {
        if (CollectionUtil.isEmpty(applyCheckIds)) {
            return;
        }
        for (String applyCheckId : applyCheckIds) {
            try {
                saveOrUpdateApplyCheckById(applyCheckId);
            } catch (Exception e) {
                log.error("导入异常管理审核{}到es报错：", applyCheckId, e);
            }
        }
    }

    @Override
    public void saveOrUpdateApplyCheckById(String applyCheckId) {
        EsApplyCheckRecord applyCheckEsModel = createApplyCheckEsModel(applyCheckId);
        if (applyCheckEsModel != null) {
            esClient.saveOrUpdate(applyCheckEsModel);
        }
    }

    private EsApplyCheckRecord createApplyCheckEsModel(String applyCheckId) {
        ApplyCheck applyCheck = applyCheckService.getById(applyCheckId);
        if (applyCheck == null) {
            return null;
        }
        boolean isWaitApplyCheck = Objects.equals(ApplyCheckState.WAIT_HANDLE.getCode(), applyCheck.getState());
        // 待审核才进入es
        if (!isWaitApplyCheck) {
            return null;
        }

        String candidateId = applyCheck.getCandidateId();
        //获取考生信息
        String ecRsp = kwClient.getExamCandidateById(candidateId);
        log.info("调用考务系统获取考生信息，：{}", ecRsp);
        ApiResponse<ExamCandidate> ecResponse = ApiResponse.ConvertRet(ecRsp, ExamCandidate.class);
        if (!Objects.equals(ecResponse.getCode(), BizStatusCode.KW_SUCCESS_OK.getCode()) || Objects.isNull(ecResponse.getData())) {
            log.error("调用考务系统获取考生信息失败，返回信息为:{}", ecResponse);
            throw new KsBizRunTimeException();
        }
        ExamCandidate examCandidate = ecResponse.getData();
//        String operatorName = userIdToNameUtil.getName(applyCheck.getOperateUser());
        return new EsApplyCheckRecord(applyCheck, examCandidate);
    }

    @Override
    public void saveOrUpdateCandidateLogOtherByIds(Set<String> logOtherIds) {
        if (CollectionUtil.isEmpty(logOtherIds)) {
            return;
        }
        for (String logOtherId : logOtherIds) {
            try {
                saveOrUpdateCandidateLogOtherById(logOtherId);
            } catch (Exception e) {
                log.error("导入异常管理{}到es报错：", logOtherId, e);
            }
        }
    }

    @Override
    public void saveOrUpdateCandidateLogOtherById(String logOtherId) {
        EsExceptionManageRecord logOtherEsModel = createLogOtherEsModel(logOtherId);
        if (logOtherEsModel != null) {
            esClient.saveOrUpdate(logOtherEsModel);
        }
    }

    private EsExceptionManageRecord createLogOtherEsModel(String logOtherId) {
        CandidateLogOther candidateLogOther = candidateLogOtherService.getById(logOtherId);
        if (candidateLogOther == null) {
            return null;
        }
        String candidateId = candidateLogOther.getCandidateId();
        //获取考生信息
        String ecRsp = kwClient.getExamCandidateById(candidateId);
        log.info("调用考务系统获取考生信息，：{}", ecRsp);
        ApiResponse<ExamCandidate> ecResponse = ApiResponse.ConvertRet(ecRsp, ExamCandidate.class);
        if (!Objects.equals(ecResponse.getCode(), BizStatusCode.KW_SUCCESS_OK.getCode()) || Objects.isNull(ecResponse.getData())) {
            log.error("调用考务系统获取考生信息失败，返回信息为:{}", ecResponse);
            throw new KsBizRunTimeException();
        }
        ExamCandidate examCandidate = ecResponse.getData();
//        String operatorName = userIdToNameUtil.getName(candidateLogOther.getOperateUser());
        String operateContent = candidateLogOther.getOperateContent();
        EsExceptionManageRecord esExceptionManageRecord = new EsExceptionManageRecord(candidateLogOther, examCandidate);
        if (AdminOperatorLogType.isCheckType(candidateLogOther.getOperateType())) {
            CandidateLogOther.OperateContent applyCheckResult = JSON.parseObject(operateContent, CandidateLogOther.OperateContent.class);
            esExceptionManageRecord.setState(applyCheckResult.getApplyResult());

            ApplyCheckMsg applyCheckMsg = applyCheckMsgService.lambdaQuery()
                    .eq(ApplyCheckMsg::getExamId, candidateLogOther.getExamId())
                    .eq(ApplyCheckMsg::getCandidateId, candidateLogOther.getCandidateId())
                    .eq(ApplyCheckMsg::getEventType, candidateLogOther.getEventType())
                    .eq(ApplyCheckMsg::getOperateType, candidateLogOther.getOperateType())
                    .orderByDesc(ApplyCheckMsg::getCreateDate).last("limit 1").one();

            boolean faceSkipPass = Objects.equals(AdminOperatorLogType.ID_CHECK_PASSED.getCode(), candidateLogOther.getOperateType() )
                    && Objects.equals(ApplyCheckState.PASSED.getCode(), applyCheckResult.getApplyResult());
            if (!faceSkipPass) {
                // 人脸核身通过不需要发送websocket消息给学生，其他的情况需要
                if (Objects.isNull(applyCheckMsg)) {
                    esExceptionManageRecord.setMsgState(WebsocketMsgSendState.SEND_SUCCESS.getCode());
                } else {
                    esExceptionManageRecord.setMsgState(applyCheckMsg.getMsgState());
                }
            }

        }
        return esExceptionManageRecord;
    }

    @Override
    public void importLogOther2eS(String examId, List<String> candidateIds) {
        List<CandidateLogOther> candidateLogOthers;
        if (CollectionUtil.isEmpty(candidateIds)) {
            candidateLogOthers =
                    candidateLogOtherService.lambdaQuery()
                            .eq(CandidateLogOther::getExamId, examId)
                            .eq(CandidateLogOther::getEventType, LogEventType.EXAMINATION_LOG.getCode())
                            .select(CandidateLogOther::getId).list();
        } else {
            candidateLogOthers =
                    candidateLogOtherService.lambdaQuery()
                            .eq(CandidateLogOther::getExamId, examId)
                            .eq(CandidateLogOther::getEventType, LogEventType.EXAMINATION_LOG.getCode())
                            .in(CandidateLogOther::getCandidateId, candidateIds)
                            .select(CandidateLogOther::getId).list();
        }
        saveOrUpdateCandidateLogOtherByIds(candidateLogOthers.stream().map(CandidateLogOther::getId).collect(Collectors.toSet()));
    }

    @Override
    public void importApplyCheck2eS(String examId, List<String> candidateIds) {
        List<ApplyCheck> applyChecks;
        if (CollectionUtil.isEmpty(candidateIds)) {
            applyChecks =
                    applyCheckService.lambdaQuery()
                            .eq(ApplyCheck::getExamId, examId)
                            .eq(ApplyCheck::getEventType, LogEventType.OPERATOR_LOG.getCode())
                            .eq(ApplyCheck::getState, ApplyCheckState.WAIT_HANDLE.getCode())
                            .select(ApplyCheck::getId).list();
        } else {
            applyChecks =
                    applyCheckService.lambdaQuery()
                            .eq(ApplyCheck::getExamId, examId)
                            .eq(ApplyCheck::getEventType, LogEventType.OPERATOR_LOG.getCode())
                            .eq(ApplyCheck::getState, ApplyCheckState.WAIT_HANDLE.getCode())
                            .in(ApplyCheck::getCandidateId, candidateIds)
                            .select(ApplyCheck::getId).list();
        }
        saveOrUpdateApplyCheckByIds(applyChecks.stream().map(ApplyCheck::getId).collect(Collectors.toSet()));
    }

    @Override
    public void deleteApplyCheckByBeforeDays(Integer beforeDays) {
        esClient.deleteApplyCheckByBeforeDays(beforeDays);
    }

    @Override
    public void deleteLogOtherByBeforeDays(Integer beforeDays) {
        esClient.deleteLogOtherByBeforeDays(beforeDays);
    }

    @Override
    public void saveCandidateOperationTrackLog(List<CandidateOperationTrackLogDTO> candidateOperationTrackLogList) {
        esClient.saveCandidateOperationTrackLog(candidateOperationTrackLogList);
    }

    @Override
    public void asyncSaveCandidateOperationTrackLog(List<CandidateOperationTrackLogDTO> candidateOperationTrackLogList) {
        esClient.asyncSaveCandidateOperationTrackLog(candidateOperationTrackLogList);
    }

    @Override
    public void deleteCandidateOperationTrackLogByExamId(String examId) {
        esClient.deleteCandidateOperationTrackLogByExamId(examId);
    }

    @Override
    public void deleteCandidateOperationTrackLogAll() {
        esClient.deleteCandidateOperationTrackLogAll();
    }

}
